package com.heaven1949.tmall.gateway.controller;

import com.gbs.saas.gateway.biz.converter.BizBOConverter;
import com.gbs.saas.gateway.biz.dto.request.RouteCfgQuery;
import com.gbs.saas.gateway.biz.dto.request.RouteCfgStatusChangeRequest;
import com.gbs.saas.gateway.biz.dto.request.RouteSaveRequest;
import com.gbs.saas.gateway.biz.dto.response.RouteCfgVO;
import com.gbs.saas.gateway.infra.common.base.PageResult;
import com.gbs.saas.gateway.infra.common.enums.ValidFlagEnum;
import com.gbs.saas.gateway.infra.common.exception.BusinessException;
import com.gbs.saas.gateway.infra.common.exception.enums.ErrorEnum;
import com.gbs.saas.gateway.infra.common.redis.RedisUtils;
import com.gbs.saas.gateway.infra.common.redis.constant.GatewayRedisKey;
import com.gbs.saas.gateway.infra.common.utils.BeanCopierUtils;
import com.gbs.saas.gateway.infra.common.utils.ConvertUtils;
import com.gbs.saas.gateway.infra.common.utils.JsonUtil;
import com.gbs.saas.gateway.infra.routecfg.model.converter.RouteDTOConverter;
import com.gbs.saas.gateway.infra.routecfg.model.dataobject.request.RouteCfgQueryDTO;
import com.gbs.saas.gateway.infra.routecfg.model.dataobject.request.RouteCfgSaveDTO;
import com.gbs.saas.gateway.infra.routecfg.model.dataobject.request.RouteCfgStatusChangeDTO;
import com.gbs.saas.gateway.infra.routecfg.model.dataobject.response.RouteCfgDO;
import com.gbs.saas.gateway.infra.routecfg.model.dataobject.response.RouteInfoDO;
import com.gbs.saas.gateway.infra.routecfg.service.RouteCfgRepository;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


/**
 * 路由配置信息维护
 * @author liwanhu
 *
 */
@Slf4j
@Service
public class RouteCfgServiceImpl implements RouteCfgService {

	@Autowired
	private RouteCfgRepository routeCfgRepository;
	@Autowired
	private DynamicRouteService dynamicRouteService;
	@Autowired
	private RedisUtils redisUtils;
	
	
	/**
	 * 验证路由配置信息的有效性
	 * @param request
	 */
	private void validateAndFormatRouteCfg(RouteSaveRequest request) {
		Lists.newArrayList(request.getPath().split(","))
		.stream().forEach(p->{
			if(!p.endsWith("/**")) {
				throw new BusinessException(ErrorEnum.ROUTE_CFG_PATH_INVALID, p);
			}
		});
//		List<RoutePredicateSaveRequest> routeFilters= request.getPredicates()==null?Lists.newArrayList():request.getPredicates();
//		routeFilters.add(RoutePredicateSaveRequest.builder()
//				.name(SystemConstant.getRoutePredicatePathName()).build()
//				.addArgs(SystemConstant.getRoutePredicateArgName(0), request.getPath()));
		
	}

	@Override
	public void saveRouteCfg(RouteSaveRequest request) {
		this.validateAndFormatRouteCfg(request);
		RouteCfgSaveDTO saveDto=BizBOConverter.convertRouteSaveRequest2DomainDTO(request);
		boolean isAdd=saveDto.getId()==null?true:false;
		try {
			this.routeCfgRepository.saveRouteCfg(saveDto);
		} catch (Exception e) {
			log.error("",e);
			throw new BusinessException(ErrorEnum.ROUTE_CFG_SAVE2DB_ERROR,e.getMessage());
		}
		try {
			//更新网关中的路由信息
			RouteCfgDO cfgDo = this.routeCfgRepository.getDetailById(saveDto.getId());
//			RouteInfoDO infoDto = BizBOConverter.convertRouteCfgDO2InfoDO(cfgDo);
			RouteInfoDO infoDo = RouteDTOConverter.convertCfg2InfoDo(cfgDo);
			log.info("{}",JsonUtil.toJsonString(infoDo));
			if(isAdd) {
				this.dynamicRouteService.addRouteInfo(infoDo);
			}else {
				//有效的路由才更新内存
				if(cfgDo.getStatus().intValue()==ValidFlagEnum.YES.getCode())
					this.dynamicRouteService.updateRouteInfo(infoDo);
			}
		} catch (BusinessException e) {
			throw e;
		}catch (Exception e) {
			log.error("",e);
			throw new BusinessException(ErrorEnum.ROUTE_CFG_SAVE2GATEWAY_ERROR,e.getMessage());
		}
		
		
	}



	@Transactional(rollbackFor = Exception.class)
	@Override
	public void deleteRouteCfg(Long id) {
		RouteCfgDO cfgDo=this.routeCfgRepository.getDetailById(id);
		if(cfgDo!=null) {
			this.routeCfgRepository.deleteRouteCfg(cfgDo);
//			RouteInfoDO infoDo = BizBOConverter.convertRouteCfgDO2InfoDO(cfgDto);

			//删除网关内存中的路由信息，后续改为mq处理
			RouteInfoDO infoDo = RouteDTOConverter.convertCfg2InfoDo(cfgDo);
			this.dynamicRouteService.deleteRouteInfo(infoDo.getRouteId());
		}
		
	}



	@Override
	public void changeRouteCfgStatus(RouteCfgStatusChangeRequest request) {
		RouteCfgDO cfgDO=this.routeCfgRepository.getDetailById(request.getId());
		if(cfgDO==null)throw new BusinessException(ErrorEnum.ROUTE_CFG_ID_NOT_EXIST);
		RouteCfgStatusChangeDTO changeDto=new RouteCfgStatusChangeDTO();
		BeanCopierUtils.copyProperties(request, changeDto);
		this.routeCfgRepository.changeRouteStatus(cfgDO,changeDto);


		RouteInfoDO infoDo = RouteDTOConverter.convertCfg2InfoDo(cfgDO);
		//启用 增加缓存路由
		if(changeDto.getStatus().intValue()== ValidFlagEnum.VALID.getCode()){
			this.dynamicRouteService.addRouteInfo(infoDo);
			//禁用--删除网关内存中的路由信息
		}else{
			this.dynamicRouteService.deleteRouteInfo(infoDo.getRouteId());
		}

	}

	@Override
	public RouteCfgVO queryDetailById(Long id) {
		RouteCfgDO dto=this.routeCfgRepository.getDetailById(id);
		return BizBOConverter.convertRouteCfgDO2VO(dto);
	}

	@Override
	public PageResult<RouteCfgVO> queryRoutePage(RouteCfgQuery query) {
		RouteCfgQueryDTO queryDto=new RouteCfgQueryDTO();
		BeanCopierUtils.copyProperties(query, queryDto);
		PageResult<RouteCfgDO> pageResult=this.routeCfgRepository.getRoutePage(queryDto);
		PageResult<RouteCfgVO> result=new PageResult<>(pageResult.getCurrent(), pageResult.getSize(), pageResult.getTotal());
		List<RouteCfgVO> records =Lists.newArrayList();
		pageResult.getRecords().stream().forEach(dto->{
			records.add(BizBOConverter.convertRouteCfgDO2VO(dto));
		});
		result.setRecords(records);
		return result;
	}



	@Override
	public List<RouteCfgDO> queryAllRouteCfg() {
		return routeCfgRepository.getAllRouteCfgs();
	}
	
	@Override
	public void refreshAllRoutes() {
		List<RouteCfgDO> cfgList= this.routeCfgRepository.getAllRouteCfgs();
		if(CollectionUtils.isEmpty(cfgList)) {
			log.warn("数据库中路由配置信息为空");
			return;
		}
		this.dynamicRouteService.refreshRouteCfgs(cfgList);
		cfgList.stream().forEach(cfgDo->{
			String cacheKey=GatewayRedisKey.genServiceInfoKey(StringUtils.join(cfgDo.getServiceId(),"#",cfgDo.getId()));
			this.redisUtils.set(cacheKey, cfgDo,GatewayRedisKey.GATEWAY_KEY_SERVICE_INFO_EXPIRE_TIME);
		});
	}

	@Override
	public List<RouteCfgVO> getServiceRoutes(String serviceId) {
		List<RouteCfgDO> cfgList=this.routeCfgRepository.getServiceRoutes(serviceId);
		return ConvertUtils.sourceToTarget(cfgList, RouteCfgVO.class);
	}

	@Override
	public RouteCfgVO getCacheServiceRoute(String serviceKey) {
		RouteCfgDO cfgDo=this.routeCfgRepository.getCacheServiceRoute(serviceKey);
		return BizBOConverter.convertRouteCfgDO2VO(cfgDo);
	}
	
	

}
